import 'dart:io';

import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:http/http.dart' as http;

extension $Image on Image {
  static String? placeholder;

  static ProgressIndicatorBuilder? loadingImageIndicatorBuilder =
      (BuildContext context, String url, DownloadProgress progress) {
    return CupertinoActivityIndicator();
  };

  static Widget loadWebImage(
    String? url, {
    Key? key,
    String? placeholder,
    bool showPlaceholderOnError = true,
    double? width,
    double? height,
    Color? backgroundColor,
    Color? color,
    BoxFit? fit,
    Alignment? alignment,
    bool applyToMemCacheSize = false,
    BorderRadius? borderRadius,
    BoxBorder? border,
    ProgressIndicatorBuilder? progressIndicatorBuilder,
  }) {
    if (url?.length == 0) {
      url = null;
    }

    if (url == null && placeholder == null) {
      assert($Image.placeholder != null);
      placeholder = $Image.placeholder;
    }

    alignment ??= Alignment.center;

    late Widget imageContent;
    if (url == null && placeholder != null) {
      imageContent = Image.asset(placeholder,
          width: width,
          height: height,
          fit: fit,
          alignment: alignment,
          color: color);
    } else {
      try {
        imageContent = CachedNetworkImage(
          imageUrl: url ?? '',
          width: width,
          height: height,
          memCacheWidth:
              applyToMemCacheSize && width != null ? width.toInt() : null,
          memCacheHeight:
              applyToMemCacheSize && height != null ? height.toInt() : null,
          progressIndicatorBuilder: progressIndicatorBuilder,
          fit: fit,
          alignment: alignment,
          color: color,
          cacheManager: _CustomImageCacheManager(),
          errorWidget: (BuildContext context, String url, dynamic error) {
            if (showPlaceholderOnError && placeholder != null) {
              return Image.asset(placeholder,
                  width: width,
                  height: height,
                  fit: fit,
                  alignment: alignment ?? Alignment.center,
                  color: color);
            }
            return Container();
          },
        );
      } catch (e) {
        debugPrint('图片加载出错:\n$e');
      }
    }

    if (borderRadius != null) {
      imageContent = ClipRRect(
        borderRadius: borderRadius,
        child: imageContent,
      );
    }

    return Container(
      child: imageContent,
      decoration: BoxDecoration(
        color: backgroundColor,
        borderRadius: borderRadius,
        border: border,
      ),
    );
  }
}

class _CustomImageCacheManager extends CacheManager with ImageCacheManager {
  static const key = 'libCachedImageData';

  static _CustomImageCacheManager? _instance;

  factory _CustomImageCacheManager() {
    _instance ??= _CustomImageCacheManager._();
    return _instance!;
  }

  _CustomImageCacheManager._()
      : super(Config(
          key,
          fileService: _ImageHttpFileService(),
        ));
}

class _ImageHttpFileService extends FileService {
  late http.Client _httpClient;

  _ImageHttpFileService({http.Client? httpClient}) {
    _httpClient = httpClient ?? http.Client();
  }

  @override
  Future<FileServiceResponse> get(String url,
      {Map<String, String>? headers}) async {
    int maxCount = 5;

    headers ??= Map<String, String>();

    String imageUrl = url;

    var httpResponse;

    var receivedCookies;
    while ((maxCount--) > 0) {
      final uri = Uri.parse(imageUrl);
      final request = http.Request('GET', uri)..followRedirects = false;
      if (receivedCookies != null) {
        headers[HttpHeaders.cookieHeader] = receivedCookies;
      }
      request.headers.addAll(headers);

      final response = await _httpClient.send(request);

      if (response.statusCode == HttpStatus.movedPermanently ||
          response.statusCode == HttpStatus.movedTemporarily) {
        String? url = response.headers[HttpHeaders.locationHeader];
        if (url != null && response.isRedirect) {
          imageUrl = url;
          receivedCookies = response.headers[HttpHeaders.setCookieHeader];
          continue;
        }
      }
      httpResponse = response;
      break;
    }

    return HttpGetResponse(httpResponse);
  }
}
